package repository

import (
	"fitness/go-admin/internal/model"
	"time"

	"gorm.io/gorm"
)

// NotificationRepository 通知仓储接口
type NotificationRepository interface {
	// 通知管理
	CreateNotification(notification *model.Notification) error
	GetNotificationByID(id uint) (*model.Notification, error)
	GetUserNotifications(userID uint, req *model.NotificationListReq) ([]model.Notification, int64, error)
	GetUnreadCount(userID uint) (int, map[string]int, error)
	MarkAsRead(notificationID, userID uint) error
	MarkBatchAsRead(notificationIDs []uint, userID uint) error
	MarkAllAsRead(userID uint, typ string) error
	DeleteNotification(notificationID, userID uint) error

	// 系统公告
	CreateAnnouncement(announcement *model.Announcement) error
	GetAnnouncementByID(id uint) (*model.Announcement, error)
	GetAnnouncements(req *model.AnnouncementListReq) ([]model.Announcement, int64, error)
	UpdateAnnouncement(announcement *model.Announcement) error
	DeleteAnnouncement(id uint) error
	PublishAnnouncement(id uint) error
	IncreaseViewCount(id uint) error

	// 通知模板
	CreateTemplate(template *model.Template) error
	GetTemplateByID(id uint) (*model.Template, error)
	GetTemplateByCode(code string) (*model.Template, error)
	GetTemplates(req *model.TemplateListReq) ([]model.Template, int64, error)
	UpdateTemplate(template *model.Template) error
	DeleteTemplate(id uint) error

	// 通知设置
	GetUserSettings(userID uint) ([]model.NotificationSetting, error)
	UpdateUserSettings(userID uint, settings []model.NotificationSetting) error
	GetUserSetting(userID uint, channel, typ string) (*model.NotificationSetting, error)

	// 系统推送
	SendCourseReminder(req *model.SendCourseReminderReq) error
	SendCardExpireReminder(req *model.SendCardExpireReq) error
	SendAnnouncement(req *model.SendAnnouncementReq) error
}

type notificationRepository struct {
	db *gorm.DB
}

func NewNotificationRepository(db *gorm.DB) NotificationRepository {
	return &notificationRepository{db: db}
}

// ==================== 通知管理 ====================

func (r *notificationRepository) CreateNotification(notification *model.Notification) error {
	return r.db.Create(notification).Error
}

func (r *notificationRepository) GetNotificationByID(id uint) (*model.Notification, error) {
	var notification model.Notification
	err := r.db.Preload("User").Preload("Template").First(&notification, id).Error
	return &notification, err
}

func (r *notificationRepository) GetUserNotifications(userID uint, req *model.NotificationListReq) ([]model.Notification, int64, error) {
	var notifications []model.Notification
	var total int64

	query := r.db.Model(&model.Notification{}).Where("user_id = ?", userID)

	// 类型筛选
	if req.Type != "" {
		query = query.Where("type = ?", req.Type)
	}

	// 已读状态筛选
	if req.IsRead != nil {
		query = query.Where("is_read = ?", *req.IsRead)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	// 排序和分页
	offset := (req.Page - 1) * req.PageSize
	err := query.Order("created_at DESC").Limit(req.PageSize).Offset(offset).Find(&notifications).Error
	return notifications, total, err
}

func (r *notificationRepository) GetUnreadCount(userID uint) (int, map[string]int, error) {
	var total int64
	err := r.db.Model(&model.Notification{}).
		Where("user_id = ? AND is_read = ?", userID, false).
		Count(&total).Error
	if err != nil {
		return 0, nil, err
	}

	// 按类型统计未读数量
	type TypeCount struct {
		Type  string
		Count int64
	}
	var typeCounts []TypeCount
	err = r.db.Model(&model.Notification{}).
		Select("type, COUNT(*) as count").
		Where("user_id = ? AND is_read = ?", userID, false).
		Group("type").
		Scan(&typeCounts).Error
	if err != nil {
		return int(total), nil, err
	}

	byType := make(map[string]int)
	for _, tc := range typeCounts {
		byType[tc.Type] = int(tc.Count)
	}

	return int(total), byType, nil
}

func (r *notificationRepository) MarkAsRead(notificationID, userID uint) error {
	return r.db.Model(&model.Notification{}).
		Where("id = ? AND user_id = ?", notificationID, userID).
		Updates(map[string]interface{}{
			"is_read": true,
			"read_at": time.Now(),
			"status":  "READ",
		}).Error
}

func (r *notificationRepository) MarkBatchAsRead(notificationIDs []uint, userID uint) error {
	return r.db.Model(&model.Notification{}).
		Where("id IN ? AND user_id = ?", notificationIDs, userID).
		Updates(map[string]interface{}{
			"is_read": true,
			"read_at": time.Now(),
			"status":  "READ",
		}).Error
}

func (r *notificationRepository) MarkAllAsRead(userID uint, typ string) error {
	updates := map[string]interface{}{
		"is_read": true,
		"read_at": time.Now(),
		"status":  "READ",
	}

	query := r.db.Model(&model.Notification{}).Where("user_id = ? AND is_read = ?", userID, false)
	if typ != "" {
		query = query.Where("type = ?", typ)
	}

	return query.Updates(updates).Error
}

func (r *notificationRepository) DeleteNotification(notificationID, userID uint) error {
	return r.db.Where("id = ? AND user_id = ?", notificationID, userID).Delete(&model.Notification{}).Error
}

// ==================== 系统公告 ====================

func (r *notificationRepository) CreateAnnouncement(announcement *model.Announcement) error {
	return r.db.Create(announcement).Error
}

func (r *notificationRepository) GetAnnouncementByID(id uint) (*model.Announcement, error) {
	var announcement model.Announcement
	err := r.db.Preload("Creator").First(&announcement, id).Error
	return &announcement, err
}

func (r *notificationRepository) GetAnnouncements(req *model.AnnouncementListReq) ([]model.Announcement, int64, error) {
	var announcements []model.Announcement
	var total int64

	query := r.db.Model(&model.Announcement{}).Where("is_published = ?", true)

	// 类型筛选
	if req.Type != "" {
		query = query.Where("type = ?", req.Type)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 10
	}

	// 排序：置顶公告优先，然后按发布时间倒序
	err := query.Order("is_top DESC, publish_at DESC, created_at DESC").
		Limit(req.PageSize).
		Offset((req.Page - 1) * req.PageSize).
		Find(&announcements).Error
	return announcements, total, err
}

func (r *notificationRepository) UpdateAnnouncement(announcement *model.Announcement) error {
	return r.db.Save(announcement).Error
}

func (r *notificationRepository) DeleteAnnouncement(id uint) error {
	return r.db.Delete(&model.Announcement{}, id).Error
}

func (r *notificationRepository) PublishAnnouncement(id uint) error {
	return r.db.Model(&model.Announcement{}).
		Where("id = ?", id).
		Updates(map[string]interface{}{
			"is_published": true,
			"publish_at":   time.Now(),
		}).Error
}

func (r *notificationRepository) IncreaseViewCount(id uint) error {
	return r.db.Model(&model.Announcement{}).
		Where("id = ?", id).
		Update("view_count", gorm.Expr("view_count + 1")).Error
}

// ==================== 通知模板 ====================

func (r *notificationRepository) CreateTemplate(template *model.Template) error {
	return r.db.Create(template).Error
}

func (r *notificationRepository) GetTemplateByID(id uint) (*model.Template, error) {
	var template model.Template
	err := r.db.First(&template, id).Error
	return &template, err
}

func (r *notificationRepository) GetTemplateByCode(code string) (*model.Template, error) {
	var template model.Template
	err := r.db.Where("code = ?", code).First(&template).Error
	return &template, err
}

func (r *notificationRepository) GetTemplates(req *model.TemplateListReq) ([]model.Template, int64, error) {
	var templates []model.Template
	var total int64

	query := r.db.Model(&model.Template{})

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 设置默认值
	if req.Page <= 0 {
		req.Page = 1
	}
	if req.PageSize <= 0 {
		req.PageSize = 20
	}

	// 排序和分页
	err := query.Order("created_at DESC").Limit(req.PageSize).Offset((req.Page - 1) * req.PageSize).Find(&templates).Error
	return templates, total, err
}

func (r *notificationRepository) UpdateTemplate(template *model.Template) error {
	return r.db.Save(template).Error
}

func (r *notificationRepository) DeleteTemplate(id uint) error {
	return r.db.Delete(&model.Template{}, id).Error
}

// ==================== 通知设置 ====================

func (r *notificationRepository) GetUserSettings(userID uint) ([]model.NotificationSetting, error) {
	var settings []model.NotificationSetting
	err := r.db.Where("user_id = ?", userID).Find(&settings).Error
	return settings, err
}

func (r *notificationRepository) UpdateUserSettings(userID uint, settings []model.NotificationSetting) error {
	// 先删除用户现有的设置
	if err := r.db.Where("user_id = ?", userID).Delete(&model.NotificationSetting{}).Error; err != nil {
		return err
	}

	// 批量创建新设置
	if len(settings) > 0 {
		return r.db.CreateInBatches(settings, 100).Error
	}

	return nil
}

func (r *notificationRepository) GetUserSetting(userID uint, channel, typ string) (*model.NotificationSetting, error) {
	var setting model.NotificationSetting
	err := r.db.Where("user_id = ? AND channel = ? AND type = ?", userID, channel, typ).First(&setting).Error
	if err != nil {
		// 如果没有找到设置，返回默认启用的设置
		defaultSetting := &model.NotificationSetting{
			UserID:    userID,
			Channel:   channel,
			Type:      typ,
			IsEnabled: true,
		}
		return defaultSetting, nil
	}
	return &setting, nil
}

// ==================== 系统推送 ====================

func (r *notificationRepository) SendCourseReminder(req *model.SendCourseReminderReq) error {
	// 根据提醒类型获取模板
	var templateCode string
	switch req.ReminderType {
	case "BOOKING_SUCCESS":
		templateCode = "COURSE_BOOKING_SUCCESS"
	case "BEFORE_CLASS":
		templateCode = "COURSE_BEFORE_CLASS"
	case "CANCELLED":
		templateCode = "COURSE_CANCELLED"
	}

	template, err := r.GetTemplateByCode(templateCode)
	if err != nil {
		return err
	}

	// 构造通知内容
	content := template.Content
	content = r.replacePlaceholder(content, "{{course_name}}", req.CourseName)
	content = r.replacePlaceholder(content, "{{class_time}}", req.ClassTime)

	title := template.Title
	title = r.replacePlaceholder(title, "{{course_name}}", req.CourseName)

	// 创建通知
	notification := &model.Notification{
		UserID:    req.UserID,
		Type:      "COURSE",
		Channel:   "INTERNAL",
		Title:     title,
		Content:   content,
		Status:    "SENT",
		SentAt:    &[]time.Time{time.Now()}[0],
		RelatedID: &req.BookingID,
	}

	return r.CreateNotification(notification)
}

func (r *notificationRepository) SendCardExpireReminder(req *model.SendCardExpireReq) error {
	// 获取模板
	template, err := r.GetTemplateByCode("CARD_EXPIRE_SOON")
	if err != nil {
		return err
	}

	// 构造通知内容
	content := template.Content
	content = r.replacePlaceholder(content, "{{card_type}}", req.CardType)
	content = r.replacePlaceholder(content, "{{days}}", string(rune(req.DaysRemaining)))

	title := template.Title
	title = r.replacePlaceholder(title, "{{card_type}}", req.CardType)
	title = r.replacePlaceholder(title, "{{days}}", string(rune(req.DaysRemaining)))

	// 创建通知
	notification := &model.Notification{
		UserID:    req.UserID,
		Type:      "CARD",
		Channel:   "INTERNAL",
		Title:     title,
		Content:   content,
		Status:    "SENT",
		SentAt:    &[]time.Time{time.Now()}[0],
		RelatedID: &req.CardID,
	}

	return r.CreateNotification(notification)
}

func (r *notificationRepository) SendAnnouncement(req *model.SendAnnouncementReq) error {
	// 获取公告详情
	announcement, err := r.GetAnnouncementByID(req.AnnouncementID)
	if err != nil {
		return err
	}

	// 创建通知
	notification := &model.Notification{
		UserID:    req.AnnouncementID, // 这里应该根据target_users来确定用户ID列表
		Type:      "SYSTEM",
		Channel:   "INTERNAL",
		Title:     announcement.Title,
		Content:   announcement.Content,
		Status:    "SENT",
		SentAt:    &[]time.Time{time.Now()}[0],
		RelatedID: &req.AnnouncementID,
	}

	return r.CreateNotification(notification)
}

// replacePlaceholder 替换模板中的占位符
func (r *notificationRepository) replacePlaceholder(template, placeholder, value string) string {
	// 简单的字符串替换实现
	result := template
	for {
		pos := len(result)
		newResult := ""
		for i := 0; i < len(result); i++ {
			if i <= len(result)-len(placeholder) && result[i:i+len(placeholder)] == placeholder {
				newResult += result[:i] + value
				result = result[i+len(placeholder):]
				i = -1 // 重置循环
			} else {
				newResult += string(result[i])
			}
		}
		if len(newResult) == pos {
			break
		}
		result = newResult
	}
	return result
}